﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;


namespace BadHabit.Factory.Views {

    /// <summary>
    /// Interaction logic for TaskSelectorWindow.xaml
    /// </summary>
    public partial class TaskSelector : Window {

        // this is a key for the FormatedWorkedTime property
        internal static readonly DependencyPropertyKey FormatedWorkedTimeKey =
            DependencyProperty.RegisterReadOnly("FormatedWorkedTime", typeof(string), typeof(TaskSelector), new PropertyMetadata(null));

        /// <summary>
        /// DP property for the FormatedWorkedTime.
        /// </summary>
        public static readonly DependencyProperty FormatedWorkedTimeProperty = FormatedWorkedTimeKey.DependencyProperty;

        // this is a key for the IsIdle property
        internal static readonly DependencyPropertyKey IsIdleKey =
            DependencyProperty.RegisterReadOnly("IsIdle", typeof(bool), typeof(TaskSelector), new PropertyMetadata(null));

        /// <summary>
        /// DP property for the IsIdle.
        /// </summary>
        public static readonly DependencyProperty IsIdleProperty = IsIdleKey.DependencyProperty;

        /// <summary>
        /// Gets the formated worked time.
        /// </summary>
        public string FormatedWorkedTime {
            get { return (string)GetValue(FormatedWorkedTimeProperty); }
        }

        public bool IsIdle {
            get {
                return (bool)GetValue(IsIdleProperty); 
            }
        }

        // used to keep the work time
        private Data.TaskDataSet.TaskResumeRow workingTask;
        private DateTime lastTimeClick;

        // slide modes
        public enum SlideMode {
            SlidingUp,
            SlidingDown,
            Stoped
        }

        // sets the animation properties
        private Duration slideDuration = new Duration(new TimeSpan(0, 0, 0, 0, 200));
        private double slideDeceleration = 0.8;

        private double topLimit;
        private RectangleGeometry clipWindow;

        public bool IsOpened { get; private set; }
        public SlideMode IsSliding { get; private set; }
        private bool IsBinding { get; set; }
        
        /// <summary>
        /// Initialize the window.
        /// </summary>
        public TaskSelector()  {
            
            InitializeComponent();

            lastTimeClick = DateTime.Now;

            IsOpened = false;
            IsSliding = SlideMode.Stoped;

            // sets the position to the screen bottom
            Left = System.Windows.SystemParameters.PrimaryScreenWidth - Width;
            Top = System.Windows.SystemParameters.WorkArea.Height;

            // creates the namescope for the animation
            NameScope.SetNameScope(this, new NameScope());
            clipWindow = new RectangleGeometry(new Rect(0, 0, Width, 0));
            Clip = clipWindow;
            RegisterName("clipWindow", clipWindow);
            RegisterName(this.Name, this);

            RegisterName(toolTipBorder.Name, toolTipBorder);

            CreateToolTipAnimation();
            
            // show it, in order to get the real Height of the window
            Show();
            Hide();
          
        }
        

        /// <summary>
        /// Gets the current task.
        /// </summary>
        public Data.TaskDataSet.TaskResumeRow CurrentTask {
            get {
                if (listView.SelectedItem == null)
                    return null;
                return ((System.Data.DataRowView)listView.SelectedItem).Row as Data.TaskDataSet.TaskResumeRow;
            }
        }

        /// <summary>
        /// Gets and sets the datacontext for a TaskResume datatable.
        /// </summary>
        private Data.TaskDataSet.TaskResumeDataTable TaskResumeDataContext {
            get {
                if (DataContext == null) {
                    Data.TaskDataSet tasks = new Data.TaskDataSet();
                    AddsIdleTask(tasks);
                    DataContext = tasks.TaskResume;
                }
                return DataContext as Data.TaskDataSet.TaskResumeDataTable;
            }
            set {
                DataContext = value;
            }
        }

        /// <summary>
        /// When the animation ends, sets sliding to stop.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sb_Completed(object sender, EventArgs e) {
            if (IsSliding == SlideMode.SlidingUp) {
                IsOpened = true;
            } else {
                IsOpened = false;
                Hide();
                ShowToolTip();
            }

            IsSliding = SlideMode.Stoped;
            
        }

        /// <summary>
        /// When the animation ends, sets sliding to stop.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void sbToolTip_Completed(object sender, EventArgs e) {
            workingToolTipPopUp.IsOpen = false;
        }

        /// <summary>
        /// Adds the idle task to the dataset.
        /// </summary>
        /// <param name="tasks">The dataset to be added the idel task</param>
        /// <returns>The idle task row</returns>
        private void AddsIdleTask(Data.TaskDataSet tasks) {
            tasks.TaskResume.AddTaskResumeRow(
                    0,
                    Client.IDLE_TASK_UID,
                    global::BadHabit.Factory.Windows.Properties.Resources.Idle,
                    Client.User.Identity.Name,
                    0,
                    DateTime.MinValue,
                    DateTime.MinValue,
                    0,
                    0,
                    0,
                    0,
                    0,
                    "",
                    DateTime.MinValue,
                    "",
                    false,
                    "",
                    0,
                    "",
                    Client.User.Identity.Name,
                    "",
                    0,
                    (short)TaskTypes.PROJECT_TASK,
                    Guid.Empty.ToString(),
                    DateTime.MinValue);            
        }

        /// <summary>
        /// Binds the tasks to the selector.
        /// </summary>
        public void Bind() {

            if (!Client.IsConnected)
                return;

            IsBinding = true;

            // temporary will store here the new task
            Data.TaskDataSet dsTask = new BadHabit.Factory.Data.TaskDataSet();

            // creates the idle task
            AddsIdleTask(dsTask);

            // reads the task from the server
            try {                                                
                dsTask.Merge(Client.Service.RetriveOpenedAssignedTasks(Client.User.Identity.Name));                
            }            
            catch (Exception ex) {
                Views.Error.ShowError(ex, global::BadHabit.Factory.Windows.Properties.Resources.COULD_NOT_READ_TASKS);
                IsBinding = false;
                return;
            }            
            
            // Verify if the current task still exists at the new tasks
            dsTask.TaskResume.DefaultView.Sort = "TaskId, TaskUId";
            System.Data.DataRowView newCurrentTask = null;
            int idx = 0;
            if (CurrentTask != null) 
                idx = dsTask.TaskResume.DefaultView.Find(new object[] { CurrentTask.TaskId, CurrentTask.TaskUId });                                           

            // if the task isnt any more availble commit the hours and change to idle
            if (idx < 0) {
                Views.Error.ShowAlert(global::BadHabit.Factory.Windows.Properties.Resources.The_task_is_no_longer_available);
                newCurrentTask = dsTask.TaskResume.DefaultView[0];  // the idle task
            }
            else
                newCurrentTask = dsTask.TaskResume.DefaultView[idx];

            // alerts for new tasks
            int rowDiff = dsTask.TaskResume.Rows.Count - TaskResumeDataContext.Rows.Count;
            if (rowDiff > 0 && dsTask.TaskResume.Rows.Count > 1)
                Client.ShowTaskAlertToolTip(rowDiff);

            // Sets the new context and current task                        
            DataContext = dsTask.TaskResume;
            listView.SelectedItem = null;  // do this cuz in case of the current task does not exists at the new tasks
            IsBinding = false;
            
            listView.SelectedItem = newCurrentTask;
            

        }      

        /// <summary>
        /// Slides the panel down.
        /// </summary>
        private void SlideDown() {
            
            if (IsSliding==SlideMode.SlidingDown)
                return;

            IsSliding = SlideMode.SlidingDown;

            // creates the storyboard
            Storyboard sb = new Storyboard();
            sb.Completed += new EventHandler(sb_Completed);

            // sets the top animation 
            DoubleAnimation animeTop = new DoubleAnimation();
            animeTop.To = System.Windows.SystemParameters.WorkArea.Height;
            animeTop.Duration = slideDuration;
            animeTop.DecelerationRatio = slideDeceleration;
            
            sb.Children.Add(animeTop);
            Storyboard.SetTargetName(animeTop, this.Name);
            Storyboard.SetTargetProperty(animeTop, new PropertyPath(Window.TopProperty));
            
            // animate it
            Topmost = false;            
            sb.Begin(this);
        }

        /// <summary>
        /// Slides the panel up.
        /// </summary>
        public void SlideUp() {

            if (IsSliding == SlideMode.SlidingUp)
                return;

            if (IsOpened)
                return;

            IsSliding = SlideMode.SlidingUp;

            Show();
            
            // sets the valuie of the current work time
            SetValue(FormatedWorkedTimeKey, FormatTime(CurrentTaskWorkedTime));
            
            // creates the storyboard
            Storyboard sb = new Storyboard();
            sb.Completed += new EventHandler(sb_Completed);
            

            // sets the clip animation
            RectAnimation animeClip = new RectAnimation();
            animeClip.From = new Rect(0, 0, Width, 0);
            animeClip.To = new Rect(0, 0, Width, ActualHeight);
            animeClip.Duration = slideDuration;
            animeClip.DecelerationRatio = slideDeceleration;
            

            sb.Children.Add(animeClip);
            Storyboard.SetTargetName(animeClip, "clipWindow" );
            Storyboard.SetTargetProperty(animeClip, new PropertyPath(RectangleGeometry.RectProperty));

            animeClip.Freeze();

            // sets the top animation 
            DoubleAnimation animeTop = new DoubleAnimation();
            animeTop.To = topLimit;
            animeTop.Duration = slideDuration;
            animeTop.DecelerationRatio = slideDeceleration;
            
            sb.Children.Add(animeTop);
            Storyboard.SetTargetName(animeTop, this.Name);
            Storyboard.SetTargetProperty(animeTop, new PropertyPath(Window.TopProperty));

            animeTop.Freeze();
            
            // animate it
            Topmost = true;
            this.BringIntoView();
            Visibility = Visibility.Visible;            
            sb.Begin(this);

            
            
        }


        /// <summary>
        /// When one task is selected, commits the old one.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listView_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            // if is binding, get out of my lukin face
            if (IsBinding)
                return;
            CommitOldSelection();            

        }

        Storyboard sbToolTip = null;

        private void CreateToolTipAnimation() {
            // creates the storyboard           
            sbToolTip = new Storyboard();
            sbToolTip.Completed += new EventHandler(sbToolTip_Completed);

            // sets the top animation 
            DoubleAnimation animeOpacity = new DoubleAnimation();
            animeOpacity.From = 1;
            animeOpacity.To = 0;
            animeOpacity.Duration = new Duration(new TimeSpan(0, 0, 4));
            
            sbToolTip.Children.Add(animeOpacity);
            Storyboard.SetTargetName(animeOpacity, toolTipBorder.Name);
            Storyboard.SetTargetProperty(animeOpacity, new PropertyPath(Border.OpacityProperty));

        }

        private void ShowToolTip() {

            if (!global::BadHabit.Factory.Windows.Properties.Settings.Default.ShowWorkingOnTaskToolTip)
                return;

            toolTipBorder.Opacity = 1;
            
            workingToolTipPopUp.IsOpen = true;            
         
            // animate it            
            sbToolTip.Begin(this);

        }

        /// <summary>
        /// Commits the old selection.
        /// </summary>
        private void CommitOldSelection() {            

            // if in fact, the task has not changed, get out of my lukin face
            if (workingTask != null && CurrentTask.TaskUId.Equals(workingTask.TaskUId))
                return;

            // commit the old task hours into the server
            if (workingTask != null) {
                bool closeTask = workingTask.Status == (short)Factory.TaskStatus.TASK_DONE;
                Client.CommitWorkedTime(workingTask.TaskUId, workingTask.TaskName, CurrentTaskWorkedTime, closeTask, CurrentTask.TaskUId);
            } else {
                
                // even 
                Client.CommitWorkedTime(null, null, new TimeSpan(), false, CurrentTask.TaskUId);
            }

            // sets the old task to the new selection
            workingTask = CurrentTask;
            lastTimeClick = DateTime.Now;

            // sets the tooltip
            string taskName = CurrentTask.TaskName;
            if (taskName.Length > 40)
                taskName = taskName.Substring(0, 40);
            Client.WorkingOnTaskName = taskName;

            if (CurrentTask.TaskUId == Client.IDLE_TASK_UID)
                SetValue(IsIdleKey, true);
            else
                SetValue(IsIdleKey, false);

            

        }
      
        /// <summary>
        /// When the size change, changes the top limit of the sliding
        /// </summary>
        /// <param name="sizeInfo"></param>
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {
            base.OnRenderSizeChanged(sizeInfo);
            topLimit = System.Windows.SystemParameters.WorkArea.Height - sizeInfo.NewSize.Height;
            if (topLimit < 0)
                topLimit = 0;

        }


        /// <summary>
        /// If the mouse leaves the window, slide it down.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void selectorWindow_MouseLeave(object sender, MouseEventArgs e) {
            SlideDown();
        }


        /// <summary>
        /// Formats the worked time to a short string.
        /// </summary>
        /// <param name="t">time</param>
        /// <returns>string formated</returns>
        private string FormatTime(TimeSpan t) {
            if (t.Days==0 && t.Hours==0 && t.Minutes == 0 && t.Seconds < 60)
                return t.Seconds + " " + global::BadHabit.Factory.Windows.Properties.Resources.sec;
            if (t.Days == 0 && t.Hours == 0 && t.Hours == 0 && t.Minutes < 60)
                return t.Minutes + " " + global::BadHabit.Factory.Windows.Properties.Resources.min;
            if (t.Days == 0 && t.Hours < 24)
                return System.Math.Round(t.TotalHours, 1) + " " + global::BadHabit.Factory.Windows.Properties.Resources.hrs;

            return System.Math.Round(t.TotalDays, 1) + " " + global::BadHabit.Factory.Windows.Properties.Resources.days;
        }

        /// <summary>
        /// Gets the amount of time spent at the current task.
        /// </summary>
        public System.TimeSpan CurrentTaskWorkedTime {
            get {
                return DateTime.Now.Subtract(lastTimeClick);
            }
        }

      

        /// <summary>
        /// Slides down, after selecting a task.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listView_MouseUp(object sender, MouseButtonEventArgs e) {
            SlideDown();            
        }

        /// <summary>
        /// Closes the clicked task.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskDone_MouseUp(object sender, MouseButtonEventArgs e) {
            // can not close the idle task
            if (CurrentTask.TaskUId == Client.IDLE_TASK_UID)
                return;

            // set the task status to done
            workingTask.Status = (short)Factory.TaskStatus.TASK_DONE;
            //CurrentTask.Status = (short)Factory.TaskStatus.TASK_DONE;
            
            // set the task to idle
            string taskUId = CurrentTask.TaskUId;
            listView.SelectedIndex = 0;            
            TaskResumeDataContext.RemoveTaskResumeRow(TaskResumeDataContext.FindByTaskUId(taskUId));
            topLimit = System.Windows.SystemParameters.WorkArea.Height - ActualHeight;
            
            SlideDown();
        }

        

        private void Hyperlink_Click(object sender, RoutedEventArgs e) {
            System.Windows.Documents.Hyperlink c = sender as System.Windows.Documents.Hyperlink;            
            Data.TaskDataSet.TaskResumeRow taskResume = Helper.GetRowFromRowView<Data.TaskDataSet.TaskResumeRow>(c.DataContext);
            if(taskResume==null)
                return;

            if (Client.IDLE_TASK_UID.Equals(taskResume.TaskUId))
                return;

            Views.TaskDetail w = new TaskDetail(taskResume.TaskId);
            w.Show();
            e.Handled = true;
        }




    }
}
